﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace Informant
{
	/// <summary>
	/// FUTURE: Replace with Unity
	/// </summary>
	public class Controller
	{
		static Controller _instance;
		readonly Dictionary<Type, Type> _types;
		readonly Dictionary<Type, Object> _instances;

		/// <summary>
		/// Gets the instance.
		/// </summary>
		/// <value>The instance.</value>
		public static Controller Instance
		{
			get
			{
				if (_instance == null)
				{
					_instance = new Controller();
				}
				return _instance;
			}
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="Controller"/> class.
		/// </summary>
		private Controller()
		{
			_types = new Dictionary<Type, Type>();
			_instances = new Dictionary<Type, Object>();
		}

		/// <summary>
		/// Gets this instance.
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <returns></returns>
		public T Get<T>()
		{
			T t = default(T);
			if (_types.Keys.Contains(typeof(T)))
			{
				t = (T)Activator.CreateInstance(_types[typeof(T)]);
			}
			else if (_instances.Keys.Contains(typeof(T)))
			{
				t = (T)_instances[typeof(T)];
			}
			return t;
		}
		/// <summary>
		/// Registers T as the key and U as the value.
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <typeparam name="U"></typeparam>
		public void Register<T, U>()
		{
			_types.Add(typeof(T), typeof(U));
		}
		/// <summary>
		/// Registers T as the key and instance of T as the value.
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="instance">The instance.</param>
		public void Register<T>(T instance)
		{
			_instances.Add(typeof(T), instance);
		}

		#region IDisposable / Finalize pattern
		bool _isDisposed = false;
		public void Dispose()
		{
			Dispose(true);
			GC.SuppressFinalize(this);
		}
		protected virtual void Dispose(bool disposing)
		{
			if (!_isDisposed)
			{
				if (disposing)
				{
					// Dispose all instances
					Int32 i = 0;
					var keysArray = _instances.Keys.ToArray();
					while (_instances.Keys.Count > 0)
					{
						var key = keysArray[i++];
						var value = _instances[key];
						_instances.Remove(key);
						var disposableValue = value as IDisposable;
						if (disposableValue != null)
						{
							disposableValue.Dispose();
						}
					}
					_types.Clear();
				}
				// Free unmanaged objects (none)
			}

			_isDisposed = true;
		}
		~Controller()
		{
			Dispose(false);
		}
		#endregion
	}
}
